Memory and Addresses
In order to use Assembly Language effectively, you'll need to understand how to access and use memory; specifically, RAM (Random Access Memory). TI83+ Memory Structure The calculator's memory is simply a long list of 1-byte storage blocks, each with its own address. For instance, the first byte's address is location 0, or $0000 in hexadecimal, the second is at $0001, the third is at $0002, etc. The addresses from $0000 to $7FFF are for the flash ROM, where archived programs and such are saved. Addresses $8000 to $FFFF are for the RAM. This adds up to 32 kilobytes of RAM; miniscule by today's modern standards, but plenty for something simple like a calculator. Of course, the things stored in RAM are items that will be changed on a regular basis, such as the location of the blinking cursor, or the image of a graph. In order to access one of these items, we first have to know what address it is stored at in the memory. Accessing Data with an Address For instance, let's say we want to know what row our cursor is on. We first would need to know that this information takes up one byte, and is stored at location $844B. Of course, we would never know this information without our ti83plus.inc file, which has labeled each of the items. Next, we can load this information from $844B into one of our registers. It is important to know the difference between loading the address and loading the value. For instance: ld hl, $844B would simply make HL hold $844B as a number. On the other hand'':'' ld a, ($844B) makes A''' hold the byte that was stored at $844B. Thus, '''A holds the value of 2. Variable Names Of course, trying to remember the number $844B is not something we want to do, especially when there are several others that we need to know too. This is why they have each been given names for easier use. For example, $844B is named CurRow (cursor row). Equates By using an equate, we can name special numbers, such as the address for CurRow. The code to do this looks like this: CurRow .EQU $844B or CurRow = $844B All this does is tell the compiler that wherever it sees "CurRow", it should use $844B instead. This of course means that we can use CurRow in place of $844B now: ld a, (CurRow); ti83p.inc has already written up all of the main equates for us. However, you can always make up our own. Like if we had an important "magic number" that we didn't want to have to remember: MagicNmber .EQU 37945 Then, every time we typed in MagicNumber it would be the same as typing in 37945. Changing Data with an Address So, let's say we want to move the cursor to a different location; 3rd column, 4th row, to be precise. We can again do this with the LD function. CurCol is the equate for the Cursor Column address ($844C, the byte right after CurRow). ld a, 4 ld (CurRow), a ld a, 3 ld (CurCol), a Note that we cannot directly load a number into CurRow; a register must be used to transfer the data. However, it is important to note that we do not need to split up a 16-bit register since we are not transferring to another 16-bit register, but rather a memory address. In fact, we can change the cursor's row and column all at once by using HL. ld hl, $0304 ;H = $03 and L = $04 ld (CurRow), hl ;L loads into CurRow, and since H won't fit, it fills in the next space, CurCol When we try to fit 16 bits into a 1-byte slot, the extra byte fills in the next slot automatically. But this brings up an EXTREMELY important point for the z80 processor. Little-Endianism When you load $0304 into HL, $03 goes to H, and $04 goes to L. So, you would think that when you load HL into (CurRow), the H would fill in CurRow and the L would fill in the next slot, CurCol, right? WRONG. The z80 processor is a "little-endian" processor, meaning the last byte, or the "little end", in a 2-byte pair is the most important. Thus, any time we LD from a 16-bit register, the last one will be taken first. This is a very confusing concept for some people; make sure you understand it fully or you could end up with a lot of "twisted around" numbers. Indirect Access